package com.uoko.common.collection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * <p>
 * 关于集合的一些操作,这个东西配合拉姆达表达式比较方便。同时对java8的集合的函数编程做了一些补充。 适合不愿意采用guava或者其他功能强大的集合操作的人做简单实用的集合操作。
 * </p>
 *
 * @author chenyingchun
 * Email qiaohai@uoko.com
 * created by 2018/6/6 0006
 */
public abstract class Collections {

    /**
     * @param <E>
     * @return
     */
    public static <E> Set<E> createMulitSet() {

        return ConcurrentHashMap.newKeySet();
    }

    /**
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> Map<K, V> createMap() {

        return new ConcurrentHashMap<K, V>();
    }

    /**
     * 创建List;
     *
     * @return
     */
    public static <v> List<v> createList() {

        return new java.util.Vector<v>();

    }

    /**
     *
     * @param <v>
     * @return
     */

    public static <v> Set<v> createSet() {

        return ConcurrentHashMap.newKeySet();
    }

    /**
     * 把源list通过转换函数转换成新的list.
     *
     * @param list
     * @param predicate
     * @return
     */
    public static <T, R> List<R> apply(Collection<T> list, Function<T, R> predicate) {
        /*如果传入为空,那么就返回null*/
        if (list == null || list.isEmpty()) {
            return null;
        }
        List<R> result = new Vector<R>();
        for (T obj : list) {
            /*判断该数据通过运算转换函数返回是否为true*/
            if (obj != null) {
                result.add(predicate.apply(obj));
            }
        }
        return result;
    }

    /**
     * 把源list通过转换函数转换成新的去重的Set.
     *
     * @param list
     * @param predicate
     * @return
     */
    public static <T, R> Set<R> applyToSet(Collection<T> list, Function<T, R> predicate) {
        /*如果传入为空,那么就返回null*/
        if (list == null || list.isEmpty()) {
            return null;
        }
        Set<R> result = new HashSet<R>();
        for (T obj : list) {
            /*判断该数据通过运算转换函数返回是否为true;*/
            if (obj != null) {
                result.add(predicate.apply(obj));
            }
        }
        return result;
    }

    /**
     * 从源Source中通过函数运行进行过滤,可以用lamda表达式调用。
     *
     * @param list
     * @param predicate
     * @return
     */
    public static <T> List<T> filter(Collection<T> list, Predicate<T> predicate) {

        /*如果传入为空,那么就返回null*/
        if (list == null || list.isEmpty()) {
            return null;
        }
        List<T> result = new Vector<T>();
        for (T obj : list) {
            /*判断该数据通过运算转换函数返回是否为true;*/
            if (obj != null && predicate.test(obj)) {
                result.add(obj);
            }
        }
        return result;
    }

    /**
     * 从源Source中通过函数运行进行第一个过滤,可以用lamda表达式调用。
     *
     * @param list
     * @param predicate
     * @return
     */
    public static <T> T getfirstItem(Collection<T> list, Predicate<T> predicate) {
        /*如果传入为空,那么就返回null*/
        if (list == null || list.isEmpty()) {
            return null;
        }
        for (T obj : list) {
            /*判断该数据通过运算转换函数返回是否为true;*/
            if (obj != null && predicate.test(obj)) {
                return obj;
            }
        }
        return null;
    }

    /**
     * 从源Source中通过比较函数找出最大值,可以用lamda表达式调用。
     *
     * @param list
     * @param comparator
     * @return
     */
    public static <T> T max(Collection<T> list, Comparator<T> comparator) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.stream().max(comparator).get();
    }

    /**
     * 从源Source中通过比较函数找出最小值,可以用lamda表达式调用。
     *
     * @param list
     * @param comparator
     * @return
     */
    public static <T> T min(Collection<T> list, Comparator<T> comparator) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.stream().min(comparator).get();

    }

    /**
     * 循环遍历Collection中的元素执行某个函数。可以用lamda表达式调用。
     *
     * @param list   操作遍历的Collection
     * @param action 遍历要执行的函数
     */
    public static <T> void forEach(Collection<T> list, Consumer<? super T> action) {
        /*如果传入为空,那么就返回null*/
        if (list == null || list.isEmpty()) {
            return;
        }
        for (T t : list) {
            action.accept(t);
        }
    }

    /**
     * 循环遍历map中的元素执行某个函数。可以用lamda表达式调用。
     *
     * @param sourceMap 操作遍历map
     * @param action    遍历要执行的函数
     */
    public static <T, U> void forEach(Map<T, U> sourceMap, BiConsumer<T, U> action) {
        /*如果传入为空,那么就返回null*/
        if (sourceMap == null || sourceMap.isEmpty()) {
            return;
        }
        sourceMap.forEach(action);
    }

    /**
     * 根据传入条件函数，遍历Collection把符合条件的删除,可以用lamda表达式调用。
     *
     * @param collection 操作Collection
     * @param action     条件函数
     */
    public static <T> void remove(Collection<T> collection, Predicate<T> action) {
        if (collection != null) {
            Iterator<T> it = collection.iterator();
            while (it.hasNext()) {
                T entry = it.next();
                if (action.test(entry)) {
                    it.remove(); // OK
                }
            }
        }
    }

    /**
     * 根据传入条件函数，遍历map把符合条件的删除,可以用lamda表达式调用。
     *
     * @param sourceMap 操作map
     * @param action    条件函数
     */
    public static <T, U> void remove(Map<T, U> sourceMap, BiPredicate<T, U> action) {
        if (sourceMap != null) {
            Iterator<Map.Entry<T, U>> it = sourceMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<T, U> entry = it.next();
                if (action.test(entry.getKey(), entry.getValue())) {
                    it.remove(); // OK
                }
            }
        }
    }

    /**
     * 排序,按照默认排序，主要是针对int,日期等这类类型的,不需要写排序器。
     *
     * @param collection
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> sorted(Collection<T> collection) {
        if (collection == null | collection.isEmpty()) {
            return null;
        }
        return Arrays.asList((T[]) collection.stream().sorted().toArray());
    }

    /**
     * 排序需要引入排序器
     *
     * @param collection
     * @param comparator
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> sorted(Collection<T> collection, Comparator<? super T> comparator) {
        if (collection == null | collection.isEmpty()) {
            return null;
        }
        return Arrays.asList((T[]) collection.stream().sorted(comparator).toArray());
    }

    /**
     * tomap 把一个list转换成map
     *
     * @param list
     * @param action
     * @return
     */
    public static <K, V> Map<K, V> toMap(Collection<V> list, Function<V, K> action) {

        if (list == null || list.isEmpty()) {
            return null;
        }
        Map<K, V> resMap = new HashMap<>();
        for (V value : list) {
            resMap.put(action.apply(value), value);
        }
        return resMap;
    }

    /**
     * 根据action建立索引，然后通过比较器返回最小一条记录。
     *
     * @param list
     * @param action
     * @param comparator
     * @return
     */
    public static <K, V> Map<K, V> toMapOneMin(Collection<V> list, Function<V, K> action, Comparator<V> comparator) {

        if (list == null || list.isEmpty()) {
            return null;
        }
        Map<K, V> resMap = new HashMap<>();
        for (V value : list) {
            K key = action.apply(value);
            V old = resMap.get(key);
            if (old == null || comparator.compare(old, value) > 0) {
                resMap.put(key, value);
            }
        }
        return resMap;
    }

    /**
     * tomap 把一个list转换成mapList集合。
     *
     * @param list
     * @param action
     * @return
     */
    public static <K, V> Map<K, List<V>> toMapList(Collection<V> list, Function<V, K> action) {

        if (list == null || list.isEmpty()) {
            return null;
        }
        Map<K, List<V>> resMap = new HashMap<>();
        for (V value : list) {
            K key = action.apply(value);
            if (key != null) {
                List<V> tempList = resMap.get(key);
                if (tempList == null) {
                    tempList = new ArrayList<>();
                    resMap.put(key, tempList);
                }
                tempList.add(value);
            }
        }
        return resMap;
    }

    /**
     * toMapSubMap 把一个list转换成两层的Map,这个在雪花结构中常有用。例如：根据第一个字段作为第一层Key,第二个字段作为第二层key建立索引。
     *
     * @param list
     * @param action
     * @return
     */
    public static <K1, K2, V> Map<K1, Map<K2, V>> toMapSubMap(Collection<V> list, Function<V, K1> action, Function<V, K2> subAction) {

        if (list == null || list.isEmpty()) {
            return null;
        }
        Map<K1, Map<K2, V>> resMap = new HashMap<>();
        for (V value : list) {
            K1 key1 = action.apply(value);
            Map<K2, V> tempMap = resMap.get(key1);
            if (tempMap == null) {
                tempMap = new HashMap<>();
                resMap.put(key1, tempMap);
            }
            K2 key2 = subAction.apply(value);
            tempMap.put(key2, value);
        }
        return resMap;
    }

    /**
     * 取前N条记录子集合
     *
     * @param collection
     * @param count
     * @return
     */
    public static <T> List<T> subList(Collection<T> collection, int count) {
        if (collection == null || collection.isEmpty() || count <= 0) {
            return null;
        }
        List<T> result = new Vector<T>();
        int i = 0;
        for (T t : collection) {
            result.add(t);
            i++;
            if (i == count) {
                break;
            }
        }
        return result;
    }

    /**
     * 取符合函数action条件的前N条记录
     *
     * @param collection
     * @param count
     * @param action
     * @return
     */
    public static <T> List<T> subList(Collection<T> collection, int count, Predicate<T> action) {
        if (collection == null || collection.isEmpty() || count <= 0 || action == null) {
            return null;
        }
        List<T> result = new Vector<T>();
        int i = 0;
        for (T t : collection) {
            if (action.test(t)) {
                result.add(t);
                i++;
                if (i == count) {
                    break;
                }
            }
        }
        return result;
    }
}
